import { PageHeader, Card, Form, Input, Select, Row, Col,Collapse,Menu, Button, Checkbox, Dropdown  } from "antd";
import { useForm } from "antd/lib/form/Form";
import { useEffect, useContext, useState } from "react";
import { CaretRightOutlined,PlusOutlined,MinusOutlined  } from "@ant-design/icons";

const {Option} = Select;
const {Panel} = Collapse;

export function RequestBody(props:{name: string, initData?:any, initType?: string}) {
    let {name, initData, initType} = props;
    const [nodes, setNodes] = useState(initData?initData:[{
        lv: 1,
        name: "",
        note: "",
        type: "string",
        value: "",
        must: true
    }]);
    const [type, setType] = useState(initType?initType:"json");


    const MOD = {
        onTypeChanged: (v: string, index: number) => {
            nodes[index].type = v;
            let i = index + 1;
            while (i <= nodes.length - 1) {
                if (nodes[i].lv > nodes[index].lv) {
                    nodes.splice(i, 1);
                } else {
                    break;
                }
            }
            setNodes(nodes.slice(0));
        },
        addChild: (index: number) => {
            let i = index + 1;
            while (i <= nodes.length - 1 && nodes[i].lv - nodes[index].lv === 1) {
                i++;
            }
            nodes.splice(i, 0, {
                lv: nodes[index].lv + 1,
                name: "",
                value: "",
                type: "string",
                note: "",
                must: false
            });
            setNodes(nodes.slice(0));
        },
        addBrother: (index: number) => {
            let i = index + 1;
            while (i <= nodes.length - 1 && nodes[i].lv >= nodes[index].lv) {
                i++;
            }
            nodes.splice(i, 0, {
                lv: nodes[index].lv,
                name: "",
                value: "",
                type: "string",
                note: "",
                must: false
            });
            setNodes(nodes.slice(0));
        },
        onDelete: (index: number) => {
            let i = index + 1;
            while (i <= nodes.length - 1) {
                if (nodes[i].lv > nodes[index].lv) {
                    nodes.splice(i, 1);
                } else {
                    break;
                }
            }
            nodes.splice(index, 1);
            setNodes(nodes.slice(0));
        },
        onValueChange(v: any, n: string, index: number) {
            (nodes[index] as any)[n] = v;
            setNodes(nodes.slice(0));
        }

    }
    return (
        <>
            <Collapse
                bordered={false}
                style={{
                    backgroundColor: "#fff"
                }}
                defaultActiveKey={"1"}
            >
                <Panel header="请求体" key="1" style={{ border: "none" }}>
                    <Form labelCol={{span: 2, offset:0}} wrapperCol={{span:4}}>
                        <Form.Item label="数据格式">
                            <Select value={type} onChange={(v)=>{setType(v as string); setNodes([{lv: 1, name:"", value: "", type: "string", must: true, note: "" }])}}>
                                <Option value="json">JSON</Option>
                                <Option value="formdata">FormData</Option>
                            </Select>
                        </Form.Item>
                    </Form>
                    {setBodyForm(nodes, name, MOD, type)}
                </Panel>
            </Collapse>
        </>
    )
}

type FORMMOD = {
    onTypeChanged: (v: string, index: number) => void;
    addChild: (index: number) => void;
    addBrother: (index: number) => void;
    onDelete: (index: number) => void;
    onValueChange: (v: any, n: string, index: number) => void
}

function setBodyForm(nodes: any[], name: string, MOD: FORMMOD, type: string): React.ReactElement[] {
    let arr: React.ReactElement[] = [];
    let stack: { node: any, children: React.ReactElement[], index: number }[] = [];
    nodes.forEach((node, index) => {
        if (index === 0 || node.lv >= stack[stack.length - 1].node.lv) {
            stack.push({
                node: node,
                children: [],
                index: index
            });
        } else {
            let nodeArr: React.ReactElement[] = [];
            let prev = 0;
            while (true) {
                let temp = stack.pop() as {
                    node: any;
                    children: React.ReactElement[];
                    index: number;
                };
                if (temp?.node.lv === node.lv) {
                    temp.children = nodeArr.reverse();
                    stack.push(temp);
                    stack.push({
                        node: node,
                        children: [],
                        index: index
                    });
                    break;
                } else {
                    if (prev) {
                        if (prev === temp.node.lv) {
                            prev = temp.node.lv;
                            if (temp.children.length) {
                                nodeArr.push(
                                    <Folder
                                        key={name + temp.index}
                                        index={"" + temp.index}
                                        data={temp.node}
                                        open={true}
                                        type={temp.node.type}
                                        MOD={MOD}
                                        name={name}
                                        dataType={type}
                                    >
                                        {temp.children}
                                    </Folder>
                                );
                            } else {
                                nodeArr.push(
                                    <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD} />
                                );
                            }
                        } else {
                            prev = temp.node.lv;
                            temp.children = nodeArr.reverse();
                            stack.push(temp);
                            nodeArr = [];
                        }
                    } else {
                        prev = temp.node.lv;
                        if (temp.children.length) {
                            nodeArr.push(
                                <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD}>
                                    {temp.children}
                                </Folder>
                            );
                        } else {
                            nodeArr.push(
                                <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD} />
                            );
                        }
                    }
                }
            }
        }
    });

    let nodeArr: React.ReactElement[] = [];
    let prev = 0;
    while (true) {
        let temp = stack.pop() as {
            node: any;
            children: React.ReactElement[];
            index: number;
        };
        if (stack.length === 0) {
            if (temp.node.lv < prev) {
                arr.push(
                    <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD}>
                        {nodeArr}
                    </Folder>
                );
            } else {
                nodeArr.push(
                    <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD} />
                );
                arr = nodeArr;
            }
            break;
        } else {
            if (prev) {
                if (prev === temp.node.lv) {
                    prev = temp.node.lv;
                    if (temp.children.length) {
                        nodeArr.push(
                            <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD}>
                                {temp.children}
                            </Folder>
                        );
                    } else {
                        nodeArr.push(
                            <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD} />
                        );
                    }
                } else {
                    prev = temp.node.lv;
                    temp.children = nodeArr.reverse();
                    stack.push(temp);
                    nodeArr = [];
                }
            } else {
                prev = temp.node.lv;
                if (temp.children.length) {
                    nodeArr.push(
                        <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD}>
                            {temp.children}
                        </Folder>
                    );
                } else {
                    nodeArr.push(
                        <Folder dataType={type} name={name} key={name + temp.index} index={"" + temp.index} data={temp.node} open={true} type={temp.node.type} MOD={MOD} />
                    );
                }
            }
        }
    }
    return arr.reverse();
}

type Folderprops = {
    children?: React.ReactElement | React.ReactElement[];
    open?: boolean;
    type?: string;
    data?: any;
    index?: string;
    MOD?: FORMMOD;
    name: string;
    dataType: string
}

function Folder(props: Folderprops) {
    const { children, open, type, data, index, MOD, name } = props;
    const [isOpen, setOpen] = useState(open);
    const [form] = useForm();
    let isFolder: boolean = type === "object" || type === "array";
    const toggleOpen = () => {
        if (isFolder) {
            setOpen((isOpen) => {
                return !isOpen
            });
        }
    }
    useEffect(() => {
        form.setFieldsValue(data);
    }, [data, form]);
    const menu = (
        <Menu>
            <Menu.Item key={name + (index as string) + "b"}>
                <div onClick={() => { MOD?.addBrother(parseInt(index as string)) }}>兄弟结点</div>
            </Menu.Item>
            <Menu.Item key={name + (index as string) + "c"}>
                <div onClick={() => { MOD?.addChild(parseInt(index as string)) }}>子结点</div>
            </Menu.Item>
        </Menu>
    )

    return (
        <>
            <Form name={index} form={form} style={{ margin: "5px 0" }}>
                <Row gutter={20} align="middle">
                    <Col span={7}>
                        <div style={{ display: "flex", alignItems: "center", paddingLeft: (data.lv - 1) * 20 }}>
                            <Button type="link" size="small" onClick={toggleOpen}>
                                <CaretRightOutlined className={`openicon ${isOpen ? "open" : ""}`} style={{ opacity: isFolder ? 1 : 0 }} />
                            </Button>
                            <Form.Item
                                name={"name"}
                                noStyle
                                style={{ flexGrow: 1 }}
                            >
                                <Input onBlur={(e) => { MOD?.onValueChange(e.target.value, "name", parseInt(index as string)) }} placeholder="字段名称"></Input>
                            </Form.Item>
                        </div>
                    </Col>
                    <Col span={4}>
                        <Form.Item
                            name={"type"}
                            noStyle
                        >
                            <Select
                                placeholder="数据类型"
                                style={{ width: "100%" }}
                                onChange={(v) => { console.log(v); MOD?.onTypeChanged(v as string, parseInt(index as string)) }}
                            >
                                {props.dataType === "json" ? <>
                                    <Option value="string">String</Option>
                                    <Option value="number">Number</Option>
                                    <Option value="boolean">Boolean</Option>
                                    <Option value="array">Array</Option>
                                    <Option value="object">Object</Option>
                                </>:
                                <>
                                <Option value="string">String</Option>
                                <Option value="file">File</Option>
                                </>
                                }

                            </Select>
                        </Form.Item>
                    </Col>
                    <Col span={2}>
                        <Form.Item
                            name={"must"}
                            noStyle
                        >
                            <Checkbox
                                onChange={(e) => { MOD?.onValueChange(e.target.checked, "must", parseInt(index as string)) }}
                                style={{ textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden" }}
                                checked={data.must}>
                                必有
                            </Checkbox>
                        </Form.Item>
                    </Col>
                    <Col span={4}>
                        <Form.Item
                            name={"value"}
                            noStyle
                        >
                            <Input onBlur={(e) => { MOD?.onValueChange(e.target.value, "value", parseInt(index as string)) }} placeholder="字段值"></Input>
                        </Form.Item>
                    </Col>
                    <Col span={5}>
                        <Form.Item
                            name={"note"}
                            noStyle
                        >
                            <Input onBlur={(e) => { MOD?.onValueChange(e.target.value, "note", parseInt(index as string)) }} placeholder="备注"></Input>
                        </Form.Item>
                    </Col>
                    <Col span={2} style={{ display: "flex", flexWrap: "nowrap" }}>
                        {
                            type === "object" || type === "array"
                                ? <Dropdown overlay={menu}>
                                    <Button size="small" type="link"><PlusOutlined /></Button>
                                </Dropdown>
                                : <Button onClick={() => { MOD?.addBrother(parseInt(index as string)) }} size="small" type="link"><PlusOutlined /></Button>
                        }
                        {index === "0" ? "" : <Button onClick={() => { MOD?.onDelete(parseInt(index as string)) }} size="small" type="link"><MinusOutlined /></Button>}

                    </Col>
                </Row>
            </Form>
            <div
                className={`folder-children ${isOpen ? "open" : ""}`}
            >
                {isFolder && children ? children : ""}
            </div>
        </>
    )
}